package com.mchat.friend.service.impl;

import com.mchat.exceptions.CommonException;
import com.mchat.friend.dao.FriendRequestDAO;
import com.mchat.friend.dao.FriendDAO;
import com.mchat.friend.domain.constant.FriendRequestStatus;
import com.mchat.friend.domain.dto.FriendRequestDTO;
import com.mchat.friend.domain.dto.FriendDescribeDTO;
import com.mchat.friend.domain.dto.FriendReplyDTO;
import com.mchat.friend.domain.mapper.FriendRequestMapper;
import com.mchat.friend.domain.mapper.FriendMapper;
import com.mchat.friend.domain.po.Friend;
import com.mchat.friend.domain.po.FriendRequest;
import com.mchat.friend.domain.vo.FriendRequestVO;
import com.mchat.friend.domain.vo.FriendVO;
import com.mchat.friend.service.IFriendService;
import com.mchat.wsserver.MessageUtil;
import com.mchat.wsserver.OnlineUserMap;
import io.netty.channel.Channel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.ArrayList;

@Service
@RequiredArgsConstructor
@Slf4j
public class FriendServiceImpl implements IFriendService {
    private final FriendDAO friendDAO;
    private final FriendRequestDAO friendRequestDAO;


    public Flux<FriendRequestVO> getFriendApply(long id) {
        return friendRequestDAO.getApply(id).map(FriendRequestMapper.INSTANCE::PO2VO);
    }

    public Flux<FriendVO> getFriend(long id) {
        return friendDAO.getFriend(id).map(FriendMapper.INSTANCE::PV2VO);
    }

    public Mono<Long> setFriend(FriendDescribeDTO describe) {
        return friendDAO.updateDescribe(describe).map(count -> {
            if (count != 1) throw new CommonException("执行失败");
            return count;
        });
    }

    @Transactional
    public Mono<Long> deleteFriend(long uid, long friendId) {
        return friendDAO.deleteFriend(uid, friendId)
                .map(count -> {
                    if (count != 1) throw new CommonException("执行失败");
                    return count;
                });
    }

    @Transactional
    public Mono<Long> reply(FriendReplyDTO dto) {

        // TODO: 2025年8月10日 使用长连接通知用户

        //获取申请记录
        return friendRequestDAO.get(dto.getId()).flatMap(apply -> {
            //校验发送方接收方和状态
            if (dto.getSendId() != apply.getSendId() || dto.getReceiverId() != apply.getReceiverId() || apply.getStatus() != FriendRequestStatus.PENDING)
                return Mono.error(new CommonException("无效的申请记录"));
            if (dto.getAccept()) {
                //向好友表插入两条记录
                Friend sender = new Friend();

                sender.setUid(apply.getSendId());
                sender.setFriendId(apply.getReceiverId());
                sender.setRemarkName(apply.getRemarkName());
                sender.setUserGroup(apply.getUserGroup());

                Friend receiver = new Friend();
                receiver.setUid(apply.getReceiverId());
                receiver.setFriendId(apply.getSendId());
                receiver.setRemarkName(dto.getRemarkName());
                receiver.setUserGroup(dto.getUserGroup());

                return friendDAO.saveFriend(sender, receiver);
            }
            //让流向下继续
            return Mono.just(1);
        }).flatMap(v -> friendRequestDAO.update(dto.getId(), dto.getAccept() ? FriendRequestStatus.ACCEPTED : FriendRequestStatus.REJECTED));
    }

    @Transactional
    public Mono<FriendRequestVO> apply(FriendRequestDTO dto) {
        //查看好友关系是否存在
        return friendDAO.selectExist(dto.getSendId(), dto.getReceiverId())
                .flatMap(v -> {
                    if (v) return Mono.error(new CommonException("好友关系已经存在"));

                    ArrayList<Channel> channels = OnlineUserMap.get(dto.getReceiverId());

                    FriendRequest friendRequest = FriendRequestMapper.INSTANCE.DTO2PO(dto);
                    return friendRequestDAO.save(friendRequest).map(request->{
                        FriendRequestVO friendRequestVO = FriendRequestMapper.INSTANCE.PO2VO(request);
                        //通过websocket发送消息通知对方
                        MessageUtil.sendFriendApply(friendRequestVO);
                        return friendRequestVO;
                    });
                });
    }
}
